#ifndef __COMPILER_HPP__
#define __COMPILER_HPP__

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_compiler
{
    using namespace ns_util;
    using namespace ns_log;
    /*只负责将上传上来的代码通过程序替换g++编译成可执行程序，成功形成可执行程序，编译失败通过重定向形成错误文件*/
    class Compiler
    {
    public:
        Compiler()
        {}

        ~Compiler()
        {}

        static bool Compile(const std::string& file_name)
        {
            pid_t pid=fork();
            if(pid<0)
            {
                LOG(ERROR)<<"内部错误，创建子进程失败！！！"<<"\n";
                return false;
            }
            else if(pid==0)//子进程
            {
                /*重定向标准错误*/
                umask(0);
                int _stderr=open(PathUtil::CompileError(file_name).c_str(),O_CREAT|O_WRONLY,0664);
                if(_stderr<0)
                {
                    LOG(WARNING)<<"没有成功形成stderr文件！！！"<<"\n";
                    exit(1);
                }
                dup2(_stderr,2);//将标准错误重定向到_stderr中
                /*程序替换g++，让其执行代码文件，生成可执行文件，编译失败将失败信息重定向到错误文件中*/
                execlp("g++","g++","-o",PathUtil::Exe(file_name).c_str(),PathUtil::Src(file_name).c_str(),"-std=c++11","-D COMPILER_ONLINE",nullptr);
                LOG(ERROR)<<"启动编译器g++失败，可能是参数错误！！！"<<"\n";
                exit(2);
            }
            else//父进程
            {
                waitpid(pid,nullptr,0);//等待子进程退出
                /*判断错误文件是否生成*/
                if(FileUtil::IsFileExists(PathUtil::Exe(file_name))==false) 
                {
                    LOG(ERROR)<<"编译失败，没有形成可执行程序！！！"<<"\n";
                    return false;
                }
                LOG(INFO)<<PathUtil::Src(file_name)<<"编译成功！！！"<<"\n";
                return true;
            }
        }
    };
}

#endif